package com.chipcoo.web.utils;

import com.alibaba.fastjson.JSON;
import com.chipcoo.ResponseResult;
import com.chipcoo.models.gen.ConfSiteMatcher;
import com.chipcoo.services.ConfService;
import com.chipcoo.utils.BeanUtils;
import com.chipcoo.utils.StringUtils;
import org.apache.http.HttpHeaders;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.net.URI;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.chipcoo.shiro.filters.CoreFilter.ATTRIBUTE_KEY_CONF_SITE;
import static org.apache.commons.lang3.StringUtils.endsWithAny;
import static org.apache.commons.lang3.StringUtils.split;
import static org.apache.shiro.web.servlet.Cookie.DELETED_COOKIE_VALUE;

public final class WebUtils {
    private static ConfSiteMatcher getSite(String serverName){
        if(null==serverName||serverName.length()==0) return null;
        serverName = serverName.toLowerCase();
        List<ConfSiteMatcher> confSiteMatcherList = BeanUtils.getBean("confService", ConfService.class).selectSiteMatcher();
        for(int i=0;i<confSiteMatcherList.size();i++){
            ConfSiteMatcher item = confSiteMatcherList.get(i);
            String[] hosts = item.getHosts().split(",");
            for(int j=0;j<hosts.length;j++){
                String host = hosts[j].trim().toLowerCase();
                if(host.startsWith("*.")){
                    if( serverName.endsWith(host.substring(2)))
                        return item;
                }else if( host.equals(serverName))
                    return item;
            }
        }
        return  null;
    }
    public static ConfSiteMatcher getCurrentSite(ServletRequest req){
        if(null==req) req =getCurrentRequest();
        Object oSite = req.getAttribute(ATTRIBUTE_KEY_CONF_SITE);
        if(null==oSite)  return getSite(req.getServerName());

        return (ConfSiteMatcher)oSite;
    }

    public static HttpServletRequest getCurrentRequest(){

        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        if(null!=requestAttributes && requestAttributes instanceof ServletRequestAttributes) {
            return ((ServletRequestAttributes)requestAttributes).getRequest();
        }
        return null;
    }
    public static HttpServletResponse getCurrentResponse(){
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        if(null!=requestAttributes && requestAttributes instanceof ServletRequestAttributes) {
            return ((ServletRequestAttributes)requestAttributes).getResponse();
        }
        return null;
    }


    public static String getClientIP(HttpServletRequest request) {
        String remoteAddr = request.getHeader("X-Real-IP");
        if (StringUtils.isEmpty(remoteAddr)) {
            remoteAddr = request.getHeader("X-Forwarded-For");
            if (StringUtils.isEmpty(remoteAddr)) {
                remoteAddr = request.getHeader("Proxy-Client-IP");
                if (StringUtils.isEmpty(remoteAddr)) remoteAddr = request.getHeader("WL-Proxy-Client-IP");
            }
        }
        if (StringUtils.isEmpty(remoteAddr)){
            /*Enumeration<String> headers = request.getHeaderNames();
            remoteAddr="";
            while (headers.hasMoreElements()){
                String headerName = headers.nextElement();
                remoteAddr+=headerName+":"+request.getHeader(headerName)+"   ";
            }*/
            remoteAddr = request.getRemoteAddr();
        }
        return remoteAddr;
    }
    public static String getString(ServletRequest request,String key){
        if(null==key||key.isEmpty()) return null;
        Enumeration<String> keyList =request.getParameterNames();
        while (keyList.hasMoreElements()){
            String keyItem = keyList.nextElement();
            if(key.equalsIgnoreCase(key)){
                String found = request.getParameter(key);
                if(null!=found){
                    found =found.trim();
                    if(found.isEmpty()) found=null;
                }
                return  found;
            }
        }
        return null;
    }


    public  static  boolean isTrue(ServletRequest request,String key){
        String value = getString(request,key);
        return value != null &&
                (value.equalsIgnoreCase("true") ||
                        value.equalsIgnoreCase("t") ||
                        value.equalsIgnoreCase("1") ||
                        value.equalsIgnoreCase("enabled") ||
                        value.equalsIgnoreCase("y") ||
                        value.equalsIgnoreCase("yes") ||
                        value.equalsIgnoreCase("on"));
    }



    public static WebApplicationContext getWebApplicationContext(){
        WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();
        if(null==wac) {

            wac = (WebApplicationContext) ApplicationContextHolder.getContext();
        }
        return wac;
    }
    public static WebApplicationContext getServletApplicationContext(ServletContext servletContext){
        WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(servletContext,"org.springframework.web.servlet.FrameworkServlet.CONTEXT.springServlet");
        if(null==wac) wac = getWebApplicationContext();
        return wac;
    }


    public static void setCookie(HttpServletResponse res ,String key, String  value, int maxSeconds){
        if(null==key||key.length()<=0) return;
        Cookie cookie = new Cookie(key,value);
        cookie.setMaxAge(maxSeconds);
        res.addCookie(cookie);
    }
    public static void removeCookie(HttpServletResponse res ,String key){
        if(null==key||key.length()<=0) return;
        setCookie(res,key, DELETED_COOKIE_VALUE,0);
    }

    public static String getCookie(HttpServletRequest req,String cookieName){
        if(null==cookieName||cookieName.length()<=0) return null;

        Cookie[] cookies = req.getCookies();
        if(null==cookies) return null;
        for(int i=0;i<cookies.length;i++){
            if(cookieName.equalsIgnoreCase(cookies[i].getName())){
                return cookies[i].getValue();
            }
        }
        return null;
    }
    public final static boolean ACCESS_CONTROL_ALLOW_ORIGINS = true;
    private static void  responseJSONEnd(HttpServletRequest req ,HttpServletResponse res ,Object data) {
        if( ACCESS_CONTROL_ALLOW_ORIGINS ) {
            accessControl(req,res);
        }
        if( isHttpOptions(req) ){
            res.setHeader("Access-Control-Allow-Methods","GET,POST,PUT,DELETE");
            res.setStatus(200);
        }else {
            try {
                PrintWriter out = res.getWriter();
                out.write(JSON.toJSONString(data));
                out.flush();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

    }
    public static void responseEnd(HttpServletRequest req , HttpServletResponse res , ResponseResult responseResult){
        if(MediaTypeUtils.isAjax(req)){
             responseJSONEnd(req,res,responseResult);
        }
        else{
            String url = getURL(responseResult,req);
            if(null==url) responseJSONEnd(req,res,responseResult);
            else {
                try {
                    res.sendRedirect(url);
                }catch (Exception ex){
                    ex.printStackTrace();
                }
            }
        }
    }
    public static void accessControl(HttpServletRequest req ,HttpServletResponse res){
        String referer =getURLReferer(req);
        String referer_host = null;
        if(!StringUtils.isEmpty(referer)){
            URI uri = URI.create(referer);
            referer_host = String.format("%s://%s%s", uri.getScheme()
                    ,uri.getHost(),(uri.getPort()==80||uri.getPort()<=0)?"": String.format(":%d",uri.getPort())
            );
        }else {
            referer_host = String.format("%s://%s%s", req.getScheme()
                    ,req.getServerName(),req.getServerPort()==80?"": String.format(":%d",req.getServerPort())
            );
        }

        res.setHeader("Access-Control-Allow-Origin",referer_host);
        res.setHeader("Access-Control-Allow-Credentials", "true");

    }
    public static String getURLReferer(HttpServletRequest req){
        return req.getHeader(HttpHeaders.REFERER);
    }
    public static boolean isHttpGet(HttpServletRequest req){
        return "get".equalsIgnoreCase(req.getMethod());
    }
    public static boolean isHttpPost(HttpServletRequest req){
        return "post".equalsIgnoreCase(req.getMethod());
    }
    public static boolean isHttpOptions(HttpServletRequest req){
        return "OPTIONS".equalsIgnoreCase(req.getMethod());
    }


    public static boolean isStaticFile(String uri){

        String staticFiles = null;
        if(StringUtils.isEmpty(staticFiles))
            staticFiles = ".css,.js,.png,.jpg,.gif,.jpeg,.bmp,.ico,.swf,.psd,.htc,.crx,.xpi,.exe,.ipa,.apk";
        if (  endsWithAny(uri, split(staticFiles,"," )) ) {
            return true;
        }
        return false;
    }

    public static String getURL(ResponseResult result,HttpServletRequest request) {
        Object o = result.get(ResponseResult.KEY_REDIRECT);
        if(null==o) return null;
        HashMap<Object, Object> paramsMap = new HashMap<Object, Object>();
        for (Object oItem : ((Map) result.getData()).entrySet()) {
            Map.Entry entry = (Map.Entry) oItem;
            if (null != entry.getKey()) {
                if (!ResponseResult.KEY_REDIRECT.equalsIgnoreCase(entry.getKey().toString())) {
                    paramsMap.put(entry.getKey(), entry.getValue());
                }
            }
        }
        return getURL(o.toString(), paramsMap, true,request);
    }
    public static String getURL(String url, Map params,boolean contextRelative,HttpServletRequest request){
        StringBuilder targetUrl = new StringBuilder();
        if (contextRelative && url.startsWith("/")) {
            if(null==request) request = getCurrentRequest();
            targetUrl.append(request.getContextPath());
        }
        targetUrl.append(url);
        StringUtils.buildURLQueries(targetUrl,params,"utf-8");
        return targetUrl.toString();
    }
}
